package com.terra.ns.imp.common.web.idempotent

import com.terra.ns.imp.common.core.constant.GlobalErrorCode
import com.terra.ns.imp.common.core.exception.BaseException
import com.terra.ns.imp.common.redis.utils.RedisUtils
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.core.annotation.Order
import org.springframework.stereotype.Component
import java.time.Duration

/**
@author qins
@date 2022/4/14
@desc 实现接口幂等操作，防止重复请求
 */
@Aspect
@Component
@Order(100)
class IdempotentAspect {

    private val log: Logger = LoggerFactory.getLogger(IdempotentAspect::class.java)

    /**
     * IdempotentKeyResolver
     */
    private val idempotentKeyResolver: IdempotentKeyResolver = DefaultIdempotentKeyResolver()

    @Before("@annotation(idempotent)")
    fun beforePointCut(joinPoint: JoinPoint, idempotent: Idempotent) {
        // 解析 Key
        val key = idempotentKeyResolver.resolver(joinPoint)
        val redisKey = "idempotent:$key"
        // 锁定 Key
         val success = RedisUtils.setIfAbsent(redisKey, true, Duration.ofMillis(idempotent.timeUnit.toMillis(idempotent.timeout)))
        // 锁定失败，抛出异常
        if (!success) {
            log.error("[方法({}) 参数({}) 发现重复请求]",joinPoint.signature.toString(),joinPoint.args)
            throw BaseException(GlobalErrorCode.REPEAT_REQUEST.code, GlobalErrorCode.REPEAT_REQUEST.msg)
        }

    }

}